package ntd.util.util.metadata;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import com.ToolOpt;
import io.swagger.v3.oas.annotations.media.Schema;
import ntd.util.config.common.bo.ComDictVo;
import com.tool.ToolClass;
import ntd.util.util.UtilEnum;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class UtilMetaData {

    public static List<MetaDataBO> getAttributes(Object obj) {
        List<Field> fieldList = ListUtil.of(ToolClass.getClassByThis(obj).getDeclaredFields());
        return fieldList.stream().map(UtilMetaData::transformMetaDataBO).collect(Collectors.toList());
    }

    private static MetaDataBO transformMetaDataBO(Field field) {
        MetaDataBO typeAttribute = new MetaDataBO();
        typeAttribute.setName(field.getName());
        typeAttribute.setType(getTypeInt(field));
        typeAttribute.setDictList(handleDict(field));
        if (field.isAnnotationPresent(Schema.class)) {
            Schema annotation = field.getAnnotation(Schema.class); // 获取到属性注解
            typeAttribute.setTitle(ObjectUtil.defaultIfBlank(annotation.description(), field.getName())); // 注解值
            typeAttribute.setRequireTag(annotation.required()); // 是否必须输入
        }
        if (field.isAnnotationPresent(NtdField.class)) {
            NtdField annotation = field.getAnnotation(NtdField.class); // 获取到属性注解
            typeAttribute.setType(ObjectUtil.defaultIfNull(annotation.type(), typeAttribute.getType()));
            typeAttribute.setOneModular(annotation.oneModular());
            typeAttribute.setTwoModular(annotation.twoModular());
        }
        return typeAttribute;
    }

    private static Map<Class, Map<String, Integer>> fieldMap = MapUtil.of();

    static {
        fieldMap.put(String.class, MapUtil.of(
                Pair.of("area", 11),
                Pair.of("rich", 12),
                Pair.of("img", 13),
                Pair.of("coding", 14),
                Pair.of("link", 15),
                Pair.of("cron", 18),
                Pair.of("file", 161),
                Pair.of("files", 162),
                Pair.of("image", 163),
                Pair.of("images", 164)
        ));
        fieldMap.put(JSONArray.class, MapUtil.of(
                Pair.of("region", 41),
                Pair.of("tags", 42),
                Pair.of("params", 48),
                Pair.of("specifications", 49),
                Pair.of("_defaultVal", 44)
        ));
    }

    public static int getTypeInt(Field field) {
        final Class<?> type = field.getType();
        for (Map.Entry<Class, Map<String, Integer>> classMapEntry : fieldMap.entrySet()) {
            if (!classMapEntry.getKey().equals(type)) {
                continue;
            }
            Map<String, Integer> value = classMapEntry.getValue();
            for (Map.Entry<String, Integer> entry : value.entrySet()) {
                if (StringUtils.startsWith(field.getName(), entry.getKey())) {
                    return entry.getValue();
                }
            }
            return value.getOrDefault("_defaultVal", 1);
        }
        if (ToolClass.isNumber(type)) { // 数字类型
            return 2;
        }
        if (ToolClass.isDate(type)) { //  日期类型
            return 3;
        }
        if (BigDecimal.class == type) { // 金额类型
            return 5;
        }
        if (Boolean.class == type) { // 布尔类型
            if ("status".equals(field.getName())) {
                return 21;
            }
            return 22;
        }
        if(EnumUtil.isEnum(type)) {
            return 30;
        }
        // 类型判断失败，返回1（默认字符串）
        return 1;
    }

    private static List<ComDictVo> handleDict(Field field) {
        if (EnumUtil.isEnum(field.getType())) {
            return UtilEnum.generateDictEnum(field.getType());
        }
        String name = field.getName();
        if (StringUtils.startsWith(name, "dict")) {
            String code = StringUtils.substringAfter(name, "dict");
            return CollStreamUtil.toList(ToolOpt.OPT_S_DICT.listByCode(code), dict -> new ComDictVo(dict.getName(), dict.getId()));
        }
        return null;
    }
}
